﻿/* Copyright (c) 2010 Caleb Doise
 * 
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without restriction,
 * including without limitation the rights to use, copy, modify, merge,
 * publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;

namespace SharpScraps.Win32.Input
{

    public class InputSender
    {
        private static int s_sizeOfINPUT;

        static InputSender()
        {
            s_sizeOfINPUT = Marshal.SizeOf(new INPUT());
        }


        public static void MoveMouse(int deltaX, int deltaY)
        {
            INPUT input = new INPUT();
            MOUSEINPUT mouseInput = new MOUSEINPUT();
            mouseInput.dx = deltaX;
            mouseInput.dy = deltaY;
            mouseInput.mouseData = 0;
            mouseInput.dwFlags = MOUSEEVENTF_MOVE;
            mouseInput.dwExtraInfo = IntPtr.Zero;
            mouseInput.time = 0;
            input.mkhi.mi = mouseInput;
            SendInput(1, ref input, s_sizeOfINPUT);
        }

        public static void MouseDown(System.Windows.Forms.MouseButtons button)
        {
            INPUT input = new INPUT();
            MOUSEINPUT mouseInput = new MOUSEINPUT();
            mouseInput.dx = 0;
            mouseInput.dy = 0;
            mouseInput.mouseData = 0;
            
            mouseInput.dwFlags = 0;
            if (button == System.Windows.Forms.MouseButtons.Left)
            {
                mouseInput.dwFlags = MOUSEEVENTF_LEFTDOWN;
            }
            else if (button == System.Windows.Forms.MouseButtons.Right)
            {
                mouseInput.dwFlags = MOUSEEVENTF_RIGHTDOWN;
            }
            else if (button == System.Windows.Forms.MouseButtons.Middle)
            {
                mouseInput.dwFlags = MOUSEEVENTF_MIDDLEDOWN;
            }

            mouseInput.dwExtraInfo = IntPtr.Zero;
            mouseInput.time = 0;
            input.mkhi.mi = mouseInput;
            SendInput(1, ref input, s_sizeOfINPUT);
        }

        public static void MouseUp(System.Windows.Forms.MouseButtons button)
        {
            INPUT input = new INPUT();
            MOUSEINPUT mouseInput = new MOUSEINPUT();
            mouseInput.dx = 0;
            mouseInput.dy = 0;
            mouseInput.mouseData = 0;

            mouseInput.dwFlags = 0;
            if (button == System.Windows.Forms.MouseButtons.Left)
            {
                mouseInput.dwFlags = MOUSEEVENTF_LEFTUP;
            }
            else if (button == System.Windows.Forms.MouseButtons.Right)
            {
                mouseInput.dwFlags = MOUSEEVENTF_RIGHTUP;
            }
            else if (button == System.Windows.Forms.MouseButtons.Middle)
            {
                mouseInput.dwFlags = MOUSEEVENTF_MIDDLEUP;
            }

            mouseInput.dwExtraInfo = IntPtr.Zero;
            mouseInput.time = 0;
            input.mkhi.mi = mouseInput;
            SendInput(1, ref input, s_sizeOfINPUT);
        }



        [DllImport("user32.dll", SetLastError = true)]
        private static extern uint SendInput(uint nInputs, ref INPUT pInputs, int cbSize);


        const int INPUT_MOUSE = 0;
        const int INPUT_KEYBOARD = 1;
        const int INPUT_HARDWARE = 2;
        const uint KEYEVENTF_EXTENDEDKEY = 0x0001;
        const uint KEYEVENTF_KEYUP = 0x0002;
        const uint KEYEVENTF_UNICODE = 0x0004;
        const uint KEYEVENTF_SCANCODE = 0x0008;
        const uint XBUTTON1 = 0x0001;
        const uint XBUTTON2 = 0x0002;
        const uint MOUSEEVENTF_MOVE = 0x0001;
        const uint MOUSEEVENTF_LEFTDOWN = 0x0002;
        const uint MOUSEEVENTF_LEFTUP = 0x0004;
        const uint MOUSEEVENTF_RIGHTDOWN = 0x0008;
        const uint MOUSEEVENTF_RIGHTUP = 0x0010;
        const uint MOUSEEVENTF_MIDDLEDOWN = 0x0020;
        const uint MOUSEEVENTF_MIDDLEUP = 0x0040;
        const uint MOUSEEVENTF_XDOWN = 0x0080;
        const uint MOUSEEVENTF_XUP = 0x0100;
        const uint MOUSEEVENTF_WHEEL = 0x0800;
        const uint MOUSEEVENTF_VIRTUALDESK = 0x4000;
        const uint MOUSEEVENTF_ABSOLUTE = 0x8000;

        struct MOUSEINPUT
        {
            public int dx;
            public int dy;
            public uint mouseData;
            public uint dwFlags;
            public uint time;
            public IntPtr dwExtraInfo;
        }

        struct KEYBDINPUT
        {
            public ushort wVk;
            public ushort wScan;
            public uint dwFlags;
            public uint time;
            public IntPtr dwExtraInfo;
        }

        struct HARDWAREINPUT
        {
            public int uMsg;
            public short wParamL;
            public short wParamH;
        }

        [StructLayout(LayoutKind.Explicit)]
        struct MOUSEKEYBDHARDWAREINPUT
        {
            [FieldOffset(0)]
            public MOUSEINPUT mi;

            [FieldOffset(0)]
            public KEYBDINPUT ki;

            [FieldOffset(0)]
            public HARDWAREINPUT hi;
        }

        struct INPUT
        {
            public int type;
            public MOUSEKEYBDHARDWAREINPUT mkhi;
        }

        [DllImport("user32.dll")]
        static extern IntPtr GetMessageExtraInfo();

    }

}
